package com.kehutong.charge.service.impl;

import com.google.gson.Gson;
import com.kehutong.charge.entity.*;
import com.kehutong.charge.service.CategoryBillService;
import com.kehutong.charge.service.ChargeBillConfigService;
import com.kehutong.charge.service.CommonService;
import com.kehutong.charge.util.CommonClient;
import com.kehutong.charge.util.CommonUtil;
import com.kehutong.charge.util.ConvertUtil;
import com.kehutong.charge.util.enums.ChargeBillStatusEnum;
import com.kehutong.charge.util.enums.ChargeCalcEnum;
import com.kehutong.charge.util.enums.ChargeFeeEnum;
import com.kehutong.charge.util.enums.ChargeLogEnum;
import com.kehutong.common.DailyUtil;
import com.kehutong.common.DoveClient;
import com.kehutong.common.Java8TimeUtils;
import com.kehutong.common.dto.UniformSendReqDto;
import com.kehutong.common.enums.MessageBusinessEnum;
import com.kehutong.common.enums.TemplateType;
import com.kehutong.common.errcode.Result;
import com.kehutong.common.util.BigDecimalUtils;
import com.kehutong.common.util.TemplateReplaceUtil;
import org.bouncycastle.eac.EACCertificateHolder;
import org.coraframework.bean.Beans;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.orm.Pool;
import org.coraframework.orm.annotation.Transaction;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.connection.ThreadLocalCache;
import org.coraframework.orm.jdbc.execute.entity.FindArray;
import org.coraframework.util.Objects;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 类目账单服务类
 *
 * @author wupengfei
 */
@Transaction
public class ChargeCategoryBillServiceImpl implements CategoryBillService {

    private static final Logger logger = LoggerFactory.getLogger(ChargeCategoryBillServiceImpl.class);

    @Inject
    private CommonClient commonClient;

    @Inject
    private JdbcSession jdbcSession;

    @Inject
    private CommonService commonService;

    @Inject
    private DoveClient doveClient;

    @Inject
    private ChargeBillConfigService chargeBillConfigService;

    @Transaction
    @Override
    public Object save(ChargeBillItems chargeBillItems) throws Exception {
        logger.info("保存类目账单" + chargeBillItems.toString());

        // 获取房屋列表
        List<String> houseNoList = getHouseNo(chargeBillItems);
        return generateItemBill(chargeBillItems, houseNoList);
    }

    private Object generateItemBill(ChargeBillItems chargeBillItems, List<String> houseList) throws Exception {
        // 获取并保存出账日期
        ChargeBillConfig chargeBillConfig = chargeBillConfigService.get(chargeBillItems.getCommunityNo(), chargeBillItems.getBillYearMonth());
        if (chargeBillConfig == null) {
            chargeBillConfig = Pool.newInstance(ChargeBillConfig.class);
            chargeBillConfig.setCorpId(chargeBillItems.getRemark());
            chargeBillConfig.setCommunityName(chargeBillItems.getCommunityName());
            chargeBillConfig.setCommunityNo(chargeBillItems.getCommunityNo());
            chargeBillConfig.setBillYearMonth(chargeBillItems.getBillYearMonth());
            chargeBillConfig.setBillDate(chargeBillItems.getBillDate());
            chargeBillConfig.setPayDate(chargeBillItems.getChargeDate());
            chargeBillConfig.setDefaultDate(chargeBillItems.getPenaltyDate());
            jdbcSession.insert(chargeBillConfig);
        }

        // 是否已到出账日
        boolean isBillDate = DailyUtil.parse(chargeBillConfig.getBillDate(), "yyyy-MM-dd").before(new Date());

        Set<String> houseConfigSet = new HashSet<>();
        Set<String> houseSet = new HashSet<>();
        Set<String> readingSet = new HashSet<>();
        for (int b = 0; b < houseList.size(); b++) {
            String houseNo = houseList.get(b);

            //1、根据房屋id查询费用配置绑定项,可能配置多次
            List<ChargeHouseConfig> houseConfigList = jdbcSession.findArray(ChargeHouseConfig.class)
                    .eq("configStatus", true)
                    .eq("deleted", false).eq("houseNo", houseNo).order("createTime", "desc").exe();
            if (Objects.isEmpty(houseConfigList)) {
                logger.warn("房屋：{},没有设置收费项目ChargeHouseConfig！", houseNo);
                houseConfigSet.add(houseNo);
                continue;
            }
            ChargeHouseConfig houseConfig = houseConfigList.get(0);

            // 查询费用配置项
            FindArray<ChargeHouseSet> houseSetFindArray = jdbcSession.findArray(ChargeHouseSet.class)
                    .eq("deleted", false)
                    .eq("chargeHouseNo", houseConfig.getId());
            if (!Objects.isBlank(chargeBillItems.getChargeTypeConfigId())) {
                houseSetFindArray.eq("feeTypeNo", chargeBillItems.getChargeTypeConfigId());
            }
            List<ChargeHouseSet> houseSetList = houseSetFindArray.exe();
            if (Objects.isEmpty(houseSetList)) {
                logger.warn("房屋：{},没有设置收费项目ChargeHouseSet！", houseNo);
                houseSet.add(houseNo);
                continue;
            }

            // 判断此房屋是否有已完成已缴费的账单
            List<ChargeBillHouse> paidHouseList = jdbcSession.findArray(ChargeBillHouse.class).eq("deleted", false).eq("houseNo", houseNo)
                    .eq("billYearMonth", chargeBillItems.getBillYearMonth())
                    .eq("billStatus", ChargeBillStatusEnum.BILL_PAID_FINISH)
                    .eq("chargeStatus", ChargeBillStatusEnum.BILL_PAID).exe();
            Map<String, ChargeBillHouse> paidHouseMap = new HashMap<>();
            if (Objects.nonEmpty(paidHouseList)) {
                for (ChargeBillHouse each : paidHouseList) {
                    paidHouseMap.put(each.getUserNo(), each);
                }
            }

            // 生成未缴费的新账单（现类目账单再加上原未缴费的）
            List<ChargeBillItems> newBillItems = new ArrayList<>();
            for (int i = 0; i < houseSetList.size(); i++) {
                // 3、根据费用配置项id查询具体配置信息，并计算费用
                ChargeHouseSet chs = houseSetList.get(i);

                // 4、查询费用配置参数
                ChargeProjectConfig projectConfig = jdbcSession.findById(ChargeProjectConfig.class, chs.getProjectFeeNo());

                // 5、查询仪表类型
                ChargeTypeConfig typeConfig = jdbcSession.findById(ChargeTypeConfig.class, projectConfig.getFeeTypeNo());

                // 查询仪表配置
                MeterManage meterManage = null;
                if (!Objects.isBlank(typeConfig.getMeterTypeNo())) {
                    List<MeterManage> meterManageList = jdbcSession.findArray(MeterManage.class).eq("deleted", false).eq("meterTypeNo", typeConfig.getMeterTypeNo())
                            .eq("houseNo", houseNo).eq("status", 1).order("createTime", "desc").exe();
                    if (Objects.isEmpty(meterManageList)) {
                        logger.warn("没有配置收费仪表MeterManage");
                        houseSet.add(houseNo);
                        continue;
                    }
                    meterManage = meterManageList.get(0);
                }

                // 判断此用户是否已有成交账单
                ChargeBillHouse chargeBillHouse = paidHouseMap.get(chs.getChargeId());
                if (chargeBillHouse != null) {
                    logger.warn("房屋" + houseNo + "已有成交账单chargeId=" + chs.getChargeId());
                    houseSet.add(chs.getHouseNo());
                    continue;
                }

                // 是否一口价或按面积
                boolean isNotReadMeter = projectConfig.getCalcEnum() == ChargeCalcEnum.MODE_AREA || projectConfig.getFeeEnum() == ChargeFeeEnum.FEE_PRICE;

                ChargeBillItems items = Pool.newInstance(ChargeBillItems.class);
                String billNO = CommonUtil.generateRandom("LM");
                items.setChargeHouseSetId(chs.getId());
                items.setChargeTypeConfigId(typeConfig.getId());
                items.setItemBillNo(billNO);
                items.setBillStatus(ChargeBillStatusEnum.BILL_WAIT_PAID);
                items.setChargeStatus(ChargeBillStatusEnum.BILL_UN_PAID);
                items.setChargeProjectConfigJson(new Gson().toJson(projectConfig));

                items.setFeeTypeName(typeConfig.getFeeTypeName());
                items.setFeeTypeNo(typeConfig.getId());
                items.setChargeName(chs.getChargeName());
                items.setUserNo(chs.getChargeId());
                items.setResidentsType(chs.getReType());
                items.setCreateName(chargeBillItems.getCreateName());
                items.setBillCycleStart(chargeBillItems.getBillCycleStart());
                items.setBillCycleEnd(chargeBillItems.getBillCycleEnd());
                items.setBillDate(chargeBillItems.getBillDate());
                items.setChargeDate(chargeBillItems.getChargeDate());
                items.setDepartmentNo(chargeBillItems.getDepartmentNo());
                items.setDepartmentName(chargeBillItems.getDepartmentName());
                items.setDepartmentNos(chargeBillItems.getDepartmentNos());
                items.setCommunityNo(chargeBillItems.getCommunityNo());
                items.setCommunityName(chargeBillItems.getCommunityName());
                items.setCommunityBillNo(chargeBillItems.getCommunityBillNo());
                items.setHouseNo(chs.getHouseNo());
                items.setPrice(projectConfig.getPrice());
                items.setPenaltyDays(Java8TimeUtils.subDate(chargeBillItems.getPenaltyDate()));
                items.setPenaltyAmount(new BigDecimal(0));
                items.setPenaltyDate(chargeBillItems.getPenaltyDate());
                items.setBillYearMonth(chargeBillItems.getBillYearMonth());

                if (meterManage != null) {
                    items.setMeterTypeNo(meterManage.getMeterTypeNo());
                    items.setMeterTypeName(meterManage.getMeterTypeName());
                    items.setMeterClassifyName(meterManage.getMeterClassifyName());
                    items.setMeterClassifyNo(meterManage.getMeterClassifyNo());
                }

                // 查询阶梯数据
                if (projectConfig.getFeeEnum() == ChargeFeeEnum.FEE_LADDER) {
                    List<ChargeLadderConfig> ladderList = jdbcSession.findArray(ChargeLadderConfig.class)
                            .eq("chargeProjectNo", projectConfig.getId())
                            .order("usageStart", "asc").exe();
                    Gson gson = new Gson();
                    items.setChargeLadderConfigJson(gson.toJson(ladderList));
                }

                // 是否一口价或按面积
                List<MeterReading> meterReading = null;
                if (isNotReadMeter) {
                    //7、计算单个类型的总费用
                    BigDecimal timeUseNumber = new BigDecimal(houseConfig.getChargeArea());
                    BigDecimal amount = commonService.calcFeeCommon(projectConfig, timeUseNumber, billNO);
                    amount = amount.setScale(2, BigDecimal.ROUND_UP); //保存两位小数,只入不舍
                    items.setBillAmount(amount);
                    items.setPayableAmount(amount);

                    items.setUsageNumber(null);
                    items.setCalcUnit(null);
                    items.setLastTimeNumber(null);
                    items.setTimeNumber(null);
                    items.setStartTime(null);
                    items.setEndTime(null);
                } else {
                    // 6、根据房屋和类型、月份、周期、查询抄表使用量(有多次抄表的情况)
                    BigDecimal usageNumber = new BigDecimal(0);
                    meterReading = jdbcSession.findArray(MeterReading.class)
                            .eq("deleted", false)
                            .eq("houseNo", chs.getHouseNo())
                            .eq("meterTypeNo", typeConfig.getMeterTypeNo())
                            .like("readYearMonth", chargeBillItems.getBillYearMonth()).order("createTime", "desc")
                            .exe();
                    if (Objects.isEmpty(meterReading)) {
                        logger.warn("房间：{},在{}没有抄表数据！", chs.getHouseNo(), chargeBillItems.getBillYearMonth());
                        readingSet.add(houseNo);
                        continue;
                    }
                    MeterReading lastMeterReading = null;
                    MeterReading firstMeterReading = null;
                    for (int j = 0; j < meterReading.size(); j++) {
                        MeterReading each = meterReading.get(j);
                        if (j == 0) {
                            lastMeterReading = each;
                        }
                        if (j == meterReading.size() - 1) {
                            firstMeterReading = each;
                        }
                        usageNumber = BigDecimalUtils.add(each.getTimeUseNumber(), usageNumber, 2);
                    }
                    items.setUsageNumber(usageNumber);
                    items.setCalcUnit(lastMeterReading.getCalcUnit());
                    items.setLastTimeNumber(firstMeterReading.getLastTimeNumber());
                    items.setTimeNumber(lastMeterReading.getTimeNumber());
                    items.setStartTime(firstMeterReading.getStartTime());
                    items.setEndTime(lastMeterReading.getEndTime());

                    //7、计算单个类型的总费用
                    BigDecimal amount = commonService.calcFeeCommon(projectConfig, usageNumber, billNO);
                    amount = amount.setScale(2, BigDecimal.ROUND_UP); //保存两位小数,只入不舍
                    items.setBillAmount(amount);
                    items.setPayableAmount(amount);
                }

                JSONObject jsonOb = commonClient.getHouseById(chargeBillItems.getRemark(), houseNo);
                String communityName = jsonOb.getString("communityName");
                String buildName = jsonOb.getString("buildName");
                String mergeName = jsonOb.getString("mergeName");
                String unitName = jsonOb.getString("unitName");
                String address = ConvertUtil.jointAddress(communityName, buildName, unitName, mergeName);

                items.setBillAddress(address);
                items.setBuildNo(jsonOb.getString("buildNo"));
                items.setBuildName(buildName);
                items.setMergeName(mergeName);

                // 8、记录费用项
                newBillItems.add(items);

                // 自动关闭此类型账单
                List<ChargeBillItems> billItems = jdbcSession.findArray(ChargeBillItems.class)
                        .eq("deleted", false)
                        .eq("houseNo", houseNo)
                        .eq("billYearMonth", chargeBillItems.getBillYearMonth())
                        .eq("chargeTypeConfigId", typeConfig.getId())
                        .eq("billStatus", ChargeBillStatusEnum.BILL_WAIT_PAID)
                        .exe();
                if (billItems.size() > 0) {
                    for (ChargeBillItems each : billItems) {
                        each.setBillStatus(ChargeBillStatusEnum.BILL_PAID_CLOSE);
                        each.setRemark("自动关闭");
                    }
                    jdbcSession.updateById(billItems);
                }

                // 更改抄表统计的状态
                if (!Objects.isEmpty(meterReading)) {
                    List<MeterReadStatist> readStatists = jdbcSession.findArray(MeterReadStatist.class)
                            .eq("deleted", false)
                            .eq("houseNo", chs.getHouseNo())
                            .eq("meterTypeNo", typeConfig.getMeterTypeNo())
                            .like("readYearMonth", chargeBillItems.getBillYearMonth())
                            .exe();
                    if (!Objects.isEmpty(readStatists)) {
                        for (MeterReadStatist each : readStatists) {
                            each.setFeeStatus("3");
                        }
                        jdbcSession.updateById(readStatists);
                    }
                }

                commonService.insetLogger(items.getItemBillNo(),
                        ChargeLogEnum.LOG_CHARGE_BILL_CATE.getDesc(),
                        "创建类目账单",
                        ChargeBillStatusEnum.BILL_WAIT_PAID.getDesc(),
                        ChargeBillStatusEnum.BILL_UN_PAID.getDesc(), "操作成功", chargeBillItems.getCreateName());
            }

            if (newBillItems.size() > 0) {
                // 查询房屋账单（拆分部份待缴费的）
                List<ChargeBillItems> unpaidBillItemList = new ArrayList<>();
                List<ChargeBillHouse> unpaidList = new ArrayList<>();
                List<ChargeBillHouse> houseBillList = jdbcSession.findArray(ChargeBillHouse.class)
                        .eq("deleted", false)
                        .eq("houseNo", houseNo)
                        .eq("billStatus", ChargeBillStatusEnum.BILL_WAIT_PAID.getId())
                        .eq("billYearMonth", chargeBillItems.getBillYearMonth()).order("createTime", "desc").exe();
                if (Objects.nonEmpty(houseBillList)) {
                    // 根据状态值获取房屋账单
                    List<ChargeBillHouse> partPaidList = new ArrayList<>();
                    for (ChargeBillHouse each : houseBillList) {
                        if (each.getChargeStatus() == ChargeBillStatusEnum.BILL_UN_PAID) {
                            unpaidList.add(each);
                        } else if (each.getChargeStatus() == ChargeBillStatusEnum.BILL_PAID_PART) {
                            each.setAutoRemark("自动关闭");
                            each.setBillStatus(ChargeBillStatusEnum.BILL_PAID_CLOSE);
                            each.setChargeStatus(ChargeBillStatusEnum.BILL_UN_PAID);
                            partPaidList.add(each);
                        }
                    }

                    // 部份付费的
                    if (partPaidList.size() > 0) {
                        // 作废原账单
                        jdbcSession.updateById(partPaidList);

                        for (ChargeBillHouse each : partPaidList) {
                            commonService.insetLogger(each.getHouseBillNo(),
                                    ChargeLogEnum.LOG_CHARGE_BILL_COM.getDesc(),
                                    "常规账单作废",
                                    ChargeBillStatusEnum.BILL_PAID_CLOSE.getDesc(),
                                    ChargeBillStatusEnum.BILL_UN_PAID.getDesc(), "操作成功", chargeBillItems.getCreateName());
                        }

                        // 查询此房屋账单
                        for (ChargeBillHouse each : partPaidList) {
                            // 保存原账单信息
                            List<ChargeBillItems> houseBillItems = jdbcSession.findArray(ChargeBillItems.class).eq("houseBillNo", each.getHouseBillNo()).exe();
                            List<ChargeBillItems> newHouseBillItems = new ArrayList<>();
                            for (ChargeBillItems eachHouseBillItems : houseBillItems) {
                                ChargeBillItems newChargeBillItems = Pool.newInstance(ChargeBillItems.class);
                                Beans.from(eachHouseBillItems).to(newChargeBillItems).exclude("id").igornNull().copy();
                                newChargeBillItems.setBillStatus(ChargeBillStatusEnum.BILL_PAID_CLOSE);
                                newChargeBillItems.setChargeStatus(ChargeBillStatusEnum.BILL_UN_PAID);
                                newHouseBillItems.add(newChargeBillItems);
                            }
                            jdbcSession.insert(newHouseBillItems);

                            // 已付费的类目账单生成已缴费的新账单
                            List<ChargeBillItems> billItemIdList = jdbcSession.findArray(ChargeBillItems.class).eq("houseBillNo", each.getHouseBillNo())
                                    .eq("chargeStatus", ChargeBillStatusEnum.BILL_PAID.getId()).exe();
                            generatePaidHouseBill(each, billItemIdList);

                            // 已付费的类目账单中未付费的
                            billItemIdList = jdbcSession.findArray(ChargeBillItems.class).eq("houseBillNo", each.getHouseBillNo())
                                    .eq("billStatus", ChargeBillStatusEnum.BILL_WAIT_PAID.getId())
                                    .eq("chargeStatus", ChargeBillStatusEnum.BILL_UN_PAID.getId()).exe();
                            if (billItemIdList.size() > 0) {
                                unpaidBillItemList.addAll(billItemIdList);
                            }
                        }
                    }
                }

                // 若已过出账日则生成房屋账单
                if (isBillDate) {
                    // 用户负责的账单
                    List<ChargeBillItems> processBillItems = new ArrayList<>(newBillItems);
                    List<String> updateIdList = new ArrayList<>();
                    if (unpaidBillItemList.size() > 0) {
                        processBillItems.addAll(unpaidBillItemList);
                        updateIdList.addAll(unpaidBillItemList.stream().map(ChargeBillItems::getId).collect(Collectors.toList()));
                    }

                    Map<String, ChargeBillHouse> unpaidHouseMap = new HashMap<>();
                    for (ChargeBillHouse each : unpaidList) {
                        unpaidHouseMap.put(each.getUserNo(), each);

                        // 未付费的
                        List<ChargeBillItems> billItemIdList = jdbcSession.findArray(ChargeBillItems.class).eq("houseBillNo", each.getHouseBillNo())
                                .eq("billStatus", ChargeBillStatusEnum.BILL_WAIT_PAID.getId())
                                .eq("chargeStatus", ChargeBillStatusEnum.BILL_UN_PAID.getId()).exe();
                        if (!Objects.isEmpty(billItemIdList)) {
                            processBillItems.addAll(billItemIdList);
                            updateIdList.addAll(billItemIdList.stream().map(ChargeBillItems::getId).collect(Collectors.toList()));
                        }
                    }

                    Map<String, List<ChargeBillItems>> chargeBillMap = new HashMap<>();
                    for (ChargeBillItems each : processBillItems) {
                        List<ChargeBillItems> itemsList = chargeBillMap.computeIfAbsent(each.getUserNo(), k -> new ArrayList<>());
                        itemsList.add(each);
                    }

                    BigDecimal zero = new BigDecimal(0);
                    for (Map.Entry<String, List<ChargeBillItems>> entry : chargeBillMap.entrySet()) {
                        String userNo = entry.getKey();
                        ChargeBillHouse chargeBillHouse = unpaidHouseMap.get(userNo);
                        boolean isAdd = false;
                        if (chargeBillHouse == null) {
                            isAdd = true;
                            chargeBillHouse = generateHouseBill(chargeBillItems, houseConfig, houseNo, zero, zero);
                        }

                        List<ChargeBillItems> addItems = new ArrayList<>();
                        List<ChargeBillItems> updateItems = new ArrayList<>();
                        BigDecimal amountHouse = new BigDecimal(0);
                        for (ChargeBillItems each : entry.getValue()) {
                            amountHouse = BigDecimalUtils.add(amountHouse, each.getBillAmount(), 2);
                            each.setHouseBillNo(chargeBillHouse.getHouseBillNo());
                            if (updateIdList.contains(each.getId())) {
                                each.setItemBillNo(CommonUtil.generateRandom("LM"));
                                updateItems.add(each);
                            } else {
                                addItems.add(each);
                            }
                            each.setHouseBillNo(chargeBillHouse.getHouseBillNo());
                        }
                        chargeBillHouse.setBillAmount(amountHouse);
                        chargeBillHouse.setBillAmountUnPaid(amountHouse);
                        if (isAdd) {
                            jdbcSession.insert(chargeBillHouse);
                        } else {
                            jdbcSession.updateById(chargeBillHouse);
                        }
                        if (addItems.size() > 0) {
                            jdbcSession.insert(addItems);
                        }
                        if (updateItems.size() > 0) {
                            jdbcSession.updateById(updateItems);
                        }

                        // 发送通知
                        for (ChargeBillItems each : processBillItems) {
                            try {
                                //根据用户查询手机号码
                                JSONObject object = commonClient.findResidentInfo(userNo);

                                //切换公司
                                String companyNo = ThreadLocalCache.current().getCorpId();
                                List<String> phoneList = new ArrayList<>();
                                phoneList.add(object.getString("mobile")); //手机号
                                msgUniformSend(each, userNo, TemplateType.PAY_C_MONTH_BILL_DATE, phoneList, true, companyNo);
                            } catch (Exception e) {
                                logger.error("发送通知时异常", e);
                            }
                        }
                    }
                } else {
                    // 保存账单
                    jdbcSession.insert(newBillItems);
                }
            }
        }

        // 获取房屋信息
        Map<String, JSONObject> houseMap = getHouse(chargeBillItems.getRemark(), houseConfigSet, houseSet, readingSet);
        if (houseMap != null) {
            StringBuilder tip = new StringBuilder("房屋:");
            Set<String> buildNameSet = new HashSet<>();
            for (Map.Entry<String, JSONObject> entry : houseMap.entrySet()) {
                JSONObject houseObject = entry.getValue();
                buildNameSet.add(houseObject.getString("buildName"));
            }
            for (String each : buildNameSet) {
                tip.append(each).append(",");
            }
            tip.deleteCharAt(tip.length() - 1);
            tip.append("没有配置收费项目或抄表数据或已生成账单");
            return Result.error(2000, tip.toString());
        }

        return Result.success();
    }

    private Map<String, JSONObject> getHouse(String companyNo, Set<String> houseConfigSet, Set<String> houseSet, Set<String> readingSet) throws Exception {
        // 获取房屋信息
        Set<String> houseNoSet = new HashSet<>();
        if (houseConfigSet.size() > 0) {
            houseNoSet.addAll(houseConfigSet);
        }
        if (houseSet.size() > 0) {
            houseNoSet.addAll(houseSet);
        }
        if (readingSet.size() > 0) {
            houseNoSet.addAll(readingSet);
        }
        if (houseNoSet.size() > 0) {
            return commonClient.getHouseByIdList(companyNo, new ArrayList<>(houseNoSet));
        }
        return null;
    }

    private List<String> getHouseNo(ChargeBillItems chargeBillItems) throws Exception {
        //定义房屋集合
        List<String> result = new ArrayList<>();

        //楼栋集合
        List<String> buildNoList = chargeBillItems.getBuildNoList();
        if (!Objects.isEmpty(buildNoList)) {
            for (int i = 0; i < buildNoList.size(); i++) {
                Map<String, JSONObject> objectMap = commonClient.getBuildMap(buildNoList.get(i));
                result.addAll(objectMap.keySet());
            }
        }

        //房屋集合
        List<String> houseNoList = chargeBillItems.getHouseNoList();
        if (!Objects.isEmpty(houseNoList)) {
            result.addAll(houseNoList);
        }

        //如果楼栋和房屋都没有选，则生成整个小区账单
        result.removeAll(Collections.singleton(null));
        if (Objects.isEmpty(result)) {
            Map<String, JSONObject> objectMap = commonClient.getHouseMap(chargeBillItems.getCommunityNo());
            result.addAll(objectMap.keySet());
        }
        return result;
    }

    private ChargeBillHouse generateHouseBill(ChargeBillItems chargeBillItems, ChargeHouseConfig houseConfig,
                                              String houseNo, BigDecimal billAmount, BigDecimal billAmountUnPaid) throws Exception {
        //生成账单
        ChargeBillHouse chargeBillHouse = Pool.newInstance(ChargeBillHouse.class);
        chargeBillHouse.setHouseBillNo(CommonUtil.generateRandom("FW"));
        chargeBillHouse.setChargeName(houseConfig.getChargeName());
        chargeBillHouse.setResidentsType(houseConfig.getReType());
        chargeBillHouse.setBillYearMonth(chargeBillItems.getBillYearMonth());
        chargeBillHouse.setUserNo(houseConfig.getOwnerNo());
        chargeBillHouse.setHouseNo(houseNo);

        //查询该房屋的基本信息
        JSONObject jsonOb = commonClient.getHouseById(chargeBillItems.getRemark(), chargeBillHouse.getHouseNo());
        String communityName = jsonOb.getString("communityName");
        String buildName = jsonOb.getString("buildName");
        String mergeName = jsonOb.getString("mergeName");
        String unitName = jsonOb.getString("unitName");
        String address = ConvertUtil.jointAddress(communityName, buildName, unitName, mergeName);
        chargeBillHouse.setBillAddress(address);
        chargeBillHouse.setBuildNo(jsonOb.getString("buildNo"));
        chargeBillHouse.setBuildName(buildName);
        chargeBillHouse.setCommunityName(communityName);
        chargeBillHouse.setMergeName(mergeName);
        chargeBillHouse.setBillAmount(billAmount);
        chargeBillHouse.setBillAmountUnPaid(billAmountUnPaid);

        chargeBillHouse.setCommunityNo(chargeBillItems.getCommunityNo());
        chargeBillHouse.setCommunityBillNo(chargeBillItems.getCommunityBillNo());
        chargeBillHouse.setBillStatus(ChargeBillStatusEnum.BILL_WAIT_PAID);
        chargeBillHouse.setChargeStatus(ChargeBillStatusEnum.BILL_UN_PAID);
        chargeBillHouse.setBillCycleStart(chargeBillItems.getBillCycleStart());
        chargeBillHouse.setBillCycleEnd(chargeBillItems.getBillCycleEnd());
        chargeBillHouse.setBillDate(chargeBillItems.getBillDate());
        chargeBillHouse.setChargeDate(chargeBillItems.getChargeDate());
        chargeBillHouse.setPenaltyDate(chargeBillItems.getPenaltyDate());
        //计算违约天数,生成账单没有违约
        chargeBillHouse.setPenaltyDays(Java8TimeUtils.subDate(chargeBillItems.getPenaltyDate()));
        chargeBillHouse.setPenaltyAmount(new BigDecimal(0));
        chargeBillHouse.setDepartmentNo(chargeBillItems.getDepartmentNo());
        chargeBillHouse.setDepartmentName(chargeBillItems.getDepartmentName());
        chargeBillHouse.setDepartmentNos(chargeBillItems.getDepartmentNos());
        chargeBillHouse.setCreateName(chargeBillItems.getCreateName());

        commonService.insetLogger(chargeBillHouse.getHouseBillNo(),
                ChargeLogEnum.LOG_CHARGE_BILL_COM.getDesc(),
                "创建常规账单",
                ChargeBillStatusEnum.BILL_WAIT_PAID.getDesc(),
                ChargeBillStatusEnum.BILL_UN_PAID.getDesc(), "操作成功", chargeBillItems.getCreateName());
        return chargeBillHouse;
    }

    private void generatePaidHouseBill(ChargeBillHouse chargeBillHouse, List<ChargeBillItems> billItemIdList) {
        BigDecimal amount = BigDecimal.ZERO;
        for (ChargeBillItems each : billItemIdList) {
            amount = BigDecimalUtils.add(amount, each.getPaymentAmount(), 2);
        }
        ChargeBillHouse paidHouseBill = Pool.newInstance(ChargeBillHouse.class);
        Beans.from(chargeBillHouse).to(paidHouseBill).exclude("id").copy();
        paidHouseBill.setBillStatus(ChargeBillStatusEnum.BILL_PAID_FINISH);
        paidHouseBill.setChargeStatus(ChargeBillStatusEnum.BILL_PAID);
        paidHouseBill.setCommunityBillNo(CommonUtil.generateRandom("XQ"));
        paidHouseBill.setHouseBillNo(CommonUtil.generateRandom("FW"));
        paidHouseBill.setBillAmount(amount);
        paidHouseBill.setBillAmountPaid(amount);
        paidHouseBill.setBillAmountUnPaid(new BigDecimal(0));
        jdbcSession.insert(paidHouseBill);

        for (ChargeBillItems each : billItemIdList) {
            each.setHouseBillNo(paidHouseBill.getHouseBillNo());
            each.setItemBillNo(CommonUtil.generateRandom("LM"));
        }
        jdbcSession.updateById(billItemIdList);
    }

    /**
     * 发送消息
     *
     * @param manage       模板替换内容对象
     * @param uuid         用户ID
     * @param templateType 模板CODE
     * @param phoneList    手机号
     * @param userCreate   是否小程序用户，false 员工，true 小程序用户
     * @throws Exception
     */
    private void msgUniformSend(ChargeBillItems manage, String uuid, TemplateType templateType, List<String> phoneList, boolean userCreate, String companyNo) throws Exception {
        // 获取消息推送配置文件
        JSONObject configJson = doveClient.post("/crm/message/global/config/service/get", (http) -> {
            http.addParam("templateType", templateType.getId());
        });

        if (configJson.getIntValue("code") == 200) {
            UniformSendReqDto dto = getUniformSendReqDto(manage, uuid, templateType, phoneList, configJson.getJSONObject("data"), userCreate, companyNo);
            // 消息推送
            doveClient.post("/crm/message/service/uniformSend", (http) -> {
                http.addParam("temp", JSONObject.toJSONString(dto));
            });
        }
    }

    private UniformSendReqDto getUniformSendReqDto(ChargeBillItems manage, String uuid, TemplateType templateType,
                                                   List<String> phoneList, JSONObject dataJson, boolean userCreate,
                                                   String companyNo) throws Exception {
        UniformSendReqDto dto = new UniformSendReqDto();
        dto.setMsgId(manage.getId());
        dto.setBusinessTypeId(MessageBusinessEnum.MSG_BILL_PAY.getId());
        dto.setTemplateTypeId(templateType.getId());
        dto.setCompanyNo(companyNo);
        dto.setUserCreate(userCreate);
        dto.setUuid(uuid);
        dto.setTitle("缴费提醒");

        JSONObject inner = dataJson.getJSONObject("messageTemplateInner");
        if (dataJson.getBooleanValue("innerSend") && org.coraframework.util.Objects.nonNull(inner)) {
            dto.setTitle(inner.getString("title"));
            dto.setInnerData(TemplateReplaceUtil.replace(inner.getString("content"), inner.getString("tagArray"), manage));
            dto.setPageParam(String.format("companyNo=%s&houseNo=%s", companyNo, manage.getHouseNo()));
        }

        JSONObject sms = dataJson.getJSONObject("messageTemplateSms");
        if (dataJson.getBooleanValue("smsSend") && org.coraframework.util.Objects.nonNull(sms)) {
            if (org.coraframework.util.Objects.nonEmpty(phoneList)) {
                dto.setPhoneList(phoneList);
                dto.setSmsDataParams(TemplateReplaceUtil.listTencentSmsParam(sms.getString("content"), sms.getString("tagArray"), manage));
            } else {
                JSONObject jsonObject = doveClient.post("/kht-bin/auth/user/listPhone", http -> {
                    JSONObject temp = new JSONObject();
                    temp.put("id", Arrays.asList(uuid));
                    http.setBody(temp.toJSONString());
                });
                List<String> listPhone = JSONArray.parseArray(jsonObject.getString("data"), String.class);
                if (org.coraframework.util.Objects.nonEmpty(listPhone)) {
                    dto.setPhoneList(listPhone);
                    dto.setSmsDataParams(TemplateReplaceUtil.listTencentSmsParam(sms.getString("content"), sms.getString("tagArray"), manage));
                }
            }
        }

        String wxchatTemplate = dataJson.getString("wxchatTemplate");
        if (dataJson.getBooleanValue("wxchatSend") && org.coraframework.util.Objects.nonNull(wxchatTemplate)) {
            dto.setWxChatData(getWxchatTemplate(templateType, manage));
            dto.setPageParam(String.format("companyNo=%s&houseNo=%s", companyNo, manage.getHouseNo()));
        }

        return dto;
    }

    private String getWxchatTemplate(TemplateType templateType, ChargeBillItems manage) {
        JSONObject data = new JSONObject();

        if (TemplateType.PAY_C_MONTH_BILL_DATE == templateType) {

            data.put("first", buildMpMessageData("您的月度账单已生成"));
            // 房号
            data.put("keyword1", buildMpMessageData(manage.getBillAddress()));
            // 账单年月
            data.put("keyword2", buildMpMessageData(manage.getBillYearMonth()));
            // 账单金额
            data.put("keyword3", buildMpMessageData(BigDecimalUtils.format(manage.getBillAmount()).toPlainString()));

            data.put("remark", buildMpMessageData("感谢您的关注和支持！如有疑问，请咨询物业管理处"));
            return data.toJSONString();
        } else {
            return null;
        }
    }

    private JSONObject buildMpMessageData(String value) {
        JSONObject json = new JSONObject();
        json.put("value", value);
        return json;
    }
}
